//------------------------------------------------------------------------
// Abstract: Implement of class Memory
//
// Authoring: XiaoHanxiong
//
// Time: 2013.12.30
//
// Static test:
//
// Version history:
//		Ver_1.0 : 2013.12.30	XiaoHanxiong
//------------------------------------------------------------------------
#include "Stdafx.h"
#include "Memory.h"

namespace Library
{
	Memory::Memory()
	{
		m_base = NULL;
		m_zero = NULL;
		m_front = NULL;
		m_back = NULL;
		m_front_size = 0;
		m_back_size = 0;

		Allocate();
	}

	Memory::~Memory()
	{
		if(m_base && m_front_size != 0 && m_back_size != 0)
		{
			delete [] m_base;
		}
		m_base = NULL;
		m_zero = NULL;
		m_front = NULL;
		m_back = NULL;
	}

	bool Memory::Push( UINT8* p_value )
	{
		if(m_zero + m_back_size == m_back)
		{
			UINT8* tem_base = m_base;
			if(!Allocate(true)) return(false);
			delete [] tem_base;
		}

		*m_back++ = *p_value;

		return(true);
	}

	bool Memory::Insert( UINT8* p_value )
	{
		if(m_zero - m_front_size - 1 == m_front)
		{
			UINT8* tem_base = m_base;
			if(!Allocate(false)) return(false);
			delete [] tem_base;
		}

		*m_front-- = *p_value;

		return(true);
	}

	bool Memory::Allocate( bool flag /* =true */)
	{
		try
		{
			if(!m_base && m_front_size == 0 && m_back_size == 0)
			{
				// Allocate memory for initialize
				m_base = new byte[2*BASE_ALLOCATE];
				memset(m_base, 0, 2*BASE_ALLOCATE);

				m_front_size = BASE_ALLOCATE;
				m_back_size = BASE_ALLOCATE;
				m_zero = m_base + BASE_ALLOCATE;
				m_back = m_zero;
				m_front = m_zero - 1;

				return(true);
			}

			if(flag)
			{
				// Allocate memory to expand back memory size
				UINT8* new_base = new byte[m_front_size + 2*m_back_size];
				memset(new_base, 0, m_front_size + 2*m_back_size);
				memcpy(new_base, m_base, m_front_size+m_back_size);

				UINT8* tem_zero = m_zero;
				m_base = new_base;
				m_zero = m_base + m_front_size;
				m_front = m_zero - (tem_zero - m_front);
				m_back = m_zero + (m_back - tem_zero);

				m_back_size = m_back_size * 2;
			}
			else
			{
				// Allocate memory to expand front memory size
				UINT8* new_base = new byte[2*m_front_size + m_back_size];
				memset(new_base, 0, 2*m_front_size + m_back_size);
				memcpy(new_base+m_front_size, m_base, m_front_size+m_back_size);

				UINT8* tem_zero = m_zero;
				m_base = new_base;
				m_zero = m_base + m_front_size*2;
				m_front = m_zero - (tem_zero - m_front);
				m_back = m_zero + (m_back - tem_zero);

				m_front_size = m_front_size * 2;
			}

			return(true);
		}

		catch(.../*std::bad_alloc& e*/)
		{
			// Allocate memory fail
			return(false);
		}


		return(true);
	}

	bool Memory::Get( UINT index, UINT8* result )
	{
		UINT8* address = m_front + 1 + index; 
		if(address < m_back )
		{
			*result = *address;
			return(true);
		}
		else return(false);

	}

	bool Memory::Set( UINT index, UINT8* value )
	{
		UINT8* address = m_front + 1 + index; 
		if(address < m_back )
		{
			*address = *value;
			return(true);
		}
		else return(false);
	}

	UINT Memory::Count()
	{
		return(UINT)(m_back - m_front - 1);
	}

	Memory& Memory::operator = ( Memory& memory )
	{
		UINT dst_size = memory.m_front_size + memory.m_back_size;
		UINT src_size = m_front_size + m_back_size;

		if(&memory == this)
		{
			return(*this);
		}

		if(src_size < dst_size)
		{
			UINT8* tem_base = new byte[dst_size];
			memset(tem_base, 0, dst_size);

			delete [] m_base;
			m_base = tem_base;

			memcpy(m_base, memory.m_base, dst_size);
			m_zero = m_base + memory.m_front_size;
			m_back_size = memory.m_back_size;
			m_front_size = memory.m_front_size;
			m_front = m_zero - (memory.m_zero - memory.m_front);
			m_back = m_zero + (memory.m_back - memory.m_zero);

		}
		else
		{
			memset(m_base, 0, src_size);
			memcpy(m_base, memory.m_base, dst_size);
			m_zero = m_base + memory.m_front_size;
			m_front = m_zero - (memory.m_zero - memory.m_front);
			m_back = m_zero + (memory.m_back - memory.m_zero);
		}

		return(*this);
	}

	Memory Memory::operator + ( Memory& memory )
	{
		Memory mem;
		UINT dst_data_size = memory.m_back - memory.m_front - 1;
		UINT src_back_size = m_back_size - (m_back - m_zero);

		if(src_back_size < dst_data_size)
		{
			UINT8* new_base = new UINT8[m_front_size+m_back_size+dst_data_size];
			memset(new_base, 0, m_front_size+m_back_size+dst_data_size);
			delete [] mem.m_base;

			memcpy(new_base, m_base, m_front_size+m_back_size);
			memcpy(new_base+(m_back-m_base), memory.m_front+1, memory.Count());

			mem.m_base = new_base;
			mem.m_zero = mem.m_base + (m_zero - m_base);
			mem.m_front = mem.m_zero - (m_zero - m_front);
			mem.m_back = mem.m_zero + (m_back - m_zero) + memory.Count();
			mem.m_front_size = m_front_size;
			mem.m_back_size = m_back_size + dst_data_size;
		}
		else
		{
			mem = *this;
			memcpy(mem.m_back, memory.m_front+1, memory.Count());
			mem.m_back += memory.Count();
		}

		return(mem);
	}

}// _Library_